package mvp.cklm.testtask.dao;

import com.mongodb.*;
import mvp.cklm.testtask.converters.IMongoDBConverter;
import mvp.cklm.testtask.model.AddressModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

/**
 * Created with IntelliJ IDEA.
 * User: WORKSPOT2
 * Date: 24.02.14
 * Time: 21:19
 * To change this template use File | Settings | File Templates.
 */
public abstract class AbstractDao<K, T> implements IAbstractDao<K, T> {
    protected static final Logger log = LoggerFactory.getLogger(AbstractDao.class);
    protected DBCollection dbCollection;
    protected IMongoDBConverter<T> converter;

    public AbstractDao(MongoClient mongoClient, String dbName, Class<T> entityClass, IMongoDBConverter<T> converter) {
        DB db = mongoClient.getDB(dbName);
        this.dbCollection = db.getCollection(entityClass.getSimpleName().toLowerCase());
        this.converter = converter;
    }

    @Override
    public boolean saveObject(T model) {
        try {
            DBObject object = converter.convertToDBObject(model);
            dbCollection.save(object, WriteConcern.SAFE);
            return true;
        } catch (Exception e) {
            log.error("saveObject {}", e);
            return false;
        }
    }

    @Override
    public T getObjectById(K key) {
        try {
            DBObject req = new BasicDBObject("_id", key);
            DBObject found = dbCollection.findOne(req);
            if (found != null) {
                return converter.convertFromDBObject(found);
            }
        } catch (Exception e) {
            log.error("getObjectById {}", e);
        }
        return null;
    }

    @Override
    public long getObjectCount() {
        try {
            return dbCollection.count();
        } catch (Exception e) {
            log.error("getObjectCount {}", e);
            return -1;
        }
    }

    @Override
    public List<T> getPage(DBObject req, int page, int countOnPage) {
        List<T> toSend = new LinkedList<T>();
        try {
            DBCursor fromDB = null;
            try {
                fromDB = dbCollection.find(req).skip(page * countOnPage).limit(countOnPage);
                while (fromDB.hasNext()) {
                    toSend.add(converter.convertFromDBObject(fromDB.next()));
                }
            } finally {
                if (fromDB != null) {
                    fromDB.close();
                }
            }
        } catch (Exception e) {
            log.error("getPage {}", e);
        }
        return toSend;
    }

    @Override
    public List<T> getPage(int page, int countOnPage) {
        return getPage(new BasicDBObject(), page, countOnPage);
    }

    @Override
    public List<T> findByQuery(DBObject query) {
        List<T> toSend = new LinkedList<T>();
        try {
            DBCursor fromDB = null;
            try {
                fromDB = dbCollection.find(query);
                while (fromDB.hasNext()) {
                    toSend.add(converter.convertFromDBObject(fromDB.next()));
                }
            } finally {
                if (fromDB != null) {
                    fromDB.close();
                }
            }
        } catch (Exception e) {
            log.error("findByQuery {}", e);
        }
        return toSend;
    }

    @Override
    public K getMaxId() {
        K toReturn = null;
        try {
            DBCursor dbCursor = null;
            try {
                dbCursor = dbCollection.find().sort(new BasicDBObject("_id", -1)).limit(1);
                if (dbCursor.hasNext()) {
                    toReturn = (K) dbCursor.next().get("_id");
                }
            } finally {
                if (dbCursor != null) {
                    dbCursor.close();
                }
            }
        } catch (Exception e) {
            log.error("getMaxId {}", e);
        }
        return toReturn;
    }

    @Override
    public void dropCollection() {
        dbCollection.drop();
    }
}
